package com.xxg.renrenshoppingcart.service;

import com.alibaba.fastjson.JSON;
import com.xxg.renrencommon.api.SearchManager;
import com.xxg.renrencommon.domain.bean.Product;
import com.xxg.renrencommon.domain.bean.UserCartInfo;
import com.xxg.renrencommon.domain.dao.RenrenShopGoods;
import com.xxg.renrencommon.domain.dao.RenrenShopGoodsOption;
import com.xxg.renrencommon.exception.ShoppingCartManagerException;
import com.xxg.renrencommon.exception.exceptionenum.ShoppingCartExceptionCodeCodeEnum;
import com.xxg.renrenshoppingcart.dao.*;
import com.xxg.renrenshoppingcart.dao.bean.ShopItem;
import com.xxg.renrenshoppingcart.dao.bean.SkuItem;
import com.xxg.renrenshoppingcart.domain.query.AddBatchProductQuery;
import com.xxg.renrenshoppingcart.domain.query.AddProductQuery;
import com.xxg.renrenshoppingcart.domain.query.RemoveProductQuery;
import com.xxg.renrencommon.domain.result.BaseResult;
import com.xxg.renrenshoppingcart.domain.result.CartProductResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 购物车接口实现
 *
 * @author xxg
 * @date 2020/11/13
 */
@Slf4j
@Service
public class ShoppingCartServiceImpl implements ShoppingCartService {
    @Resource
    private UserCartInfoDao userCartInfoDao;
    @Resource
    private RenrenShopGoodsDao renrenShopGoodsDao;
    @Resource
    private RenrenShopShopDao renrenShopShopDao;
    @Resource
    private RenrenShopGoodsOptionDao renrenShopGoodsOptionDao;

    @Override
    public BaseResult<Void> addProduct(String userId, AddProductQuery query) {
        Integer userIdInt = Integer.parseInt(userId);
        Integer skuId = query.getSkuId();
        Integer spuId = query.getSpuId();
        Integer quantity = query.getQuantity();
        try {
            addToCart(userIdInt, skuId, spuId, quantity);
        } catch (ShoppingCartManagerException e) {
            return new BaseResult<>(e);
        }
        return new BaseResult<>();
    }

    private void addToCart(Integer userId, Integer skuId, Integer spuId, Integer quantity) throws ShoppingCartManagerException{
        Integer shopId = renrenShopGoodsDao.selectShopIdById(spuId);
        // 检验该商品是否存在
        if (shopId == null) {
            throw new ShoppingCartManagerException(ShoppingCartExceptionCodeCodeEnum.SKU_NOT_EXIST);
        }
        if (!skuId.equals(spuId)) {
            long count = renrenShopGoodsOptionDao.countByIdAndGoodsId(skuId, spuId);
            if (count <= 0L) {
                throw new ShoppingCartManagerException(ShoppingCartExceptionCodeCodeEnum.SKU_NOT_EXIST);
            }
        }
        // 检查是否添加过该商品
        UserCartInfo userCartInfo = userCartInfoDao.findByUserIdAndSpuIdAndSkuId(userId, spuId, skuId);
        if (userCartInfo != null) {
            userCartInfo.setQuantity(userCartInfo.getQuantity() + quantity);
            userCartInfoDao.save(userCartInfo);
        }else {
            userCartInfo = new UserCartInfo();
            userCartInfo.setUserId(userId);
            userCartInfo.setShopId(shopId);
            userCartInfo.setSpuId(spuId);
            userCartInfo.setSkuId(skuId);
            userCartInfo.setQuantity(quantity);
            userCartInfoDao.insert(userCartInfo);
        }
    }

    @Override
    public BaseResult<Void> addBatch(String userId, AddBatchProductQuery query) {
        Integer userIdInt = Integer.parseInt(userId);
        List<SkuItem> skuItems = query.getSkuItems();
        skuItems.forEach(skuItem -> {
            try {
                addToCart(userIdInt, skuItem.getSkuId(), skuItem.getSpuId(), skuItem.getQuantity());
            } catch (Exception e) {
                log.info("addBatch_error_skuItem:{}", JSON.toJSONString(skuItem));
                log.error("addBatch_error_" + e.getMessage(), e);
            }
        });
        return new BaseResult<>();
    }

    @Override
    public BaseResult<Void> updateProductQuantity(String userId, AddProductQuery query) {
        // 设置购物车中指定商品数量
        userCartInfoDao.setByUserIdSkuId(Integer.parseInt(userId), query.getSkuId(), query.getSpuId(), query.getQuantity());
        return new BaseResult<>();
    }

    @Override
    public BaseResult<Void> removeProduct(String userId, RemoveProductQuery query) {
        // 从购物车移除指定商品
        List<SkuItem> skuItems = query.getSkuItems();
        skuItems.forEach(skuItem ->
            userCartInfoDao.removeSku(Integer.parseInt(userId), skuItem.getSpuId(), skuItem.getSkuId())
        );
        return new BaseResult<>();
    }

    @Override
    public BaseResult<Void> removeAllProduct(String userId) {
        userCartInfoDao.removeByUserId(Integer.parseInt(userId));
        return new BaseResult<>();
    }

    @Override
    public BaseResult<CartProductResult> queryProducts(String userId) {
        List<UserCartInfo> userCartInfos = userCartInfoDao.findByUserId(Integer.parseInt(userId));
        if (userCartInfos == null || userCartInfos.size() <= 0) {
            return new BaseResult<>();
        }
        List<Integer> spuIds = userCartInfos.stream().map(UserCartInfo::getSpuId).collect(Collectors.toList());
        List<Integer> shopIds = userCartInfos.stream().map(UserCartInfo::getShopId).collect(Collectors.toList());
        List<RenrenShopShop> renrenShopShops = renrenShopShopDao.selectByIds(shopIds);
        Map<Integer, RenrenShopShop> shopMap = renrenShopShops.stream().collect(Collectors.toMap(RenrenShopShop::getId, renrenShopShop -> renrenShopShop));
        List<Product> products = getProducts(spuIds);
        Map<String, Product> productMap = products.stream().collect(Collectors.toMap(Product::getId, product -> product));
        final List<ShopItem> shopItems = new ArrayList<>(shopIds.size());
        final List<ShopItem> expireSkuShopItems = new ArrayList<>(shopIds.size());
        Map<Integer, List<UserCartInfo>> shopGroup = userCartInfos.stream().collect(Collectors.groupingBy(UserCartInfo::getShopId));
        shopGroup.forEach((k, v) -> {
            final List<SkuItem> skuItems = new ArrayList<>();
            final List<SkuItem> expireSkuItems = new ArrayList<>();
            v.forEach(userCartInfo -> {
                SkuItem skuItem = new SkuItem();
                Product product = productMap.get(userCartInfo.getSpuId() + "_" + userCartInfo.getSkuId());
                if (product == null) {
                    return;
                }
                skuItem.setId(userCartInfo.getId());
                skuItem.setSpuId(userCartInfo.getSpuId());
                skuItem.setSkuId(userCartInfo.getSkuId());
                skuItem.setQuantity(userCartInfo.getQuantity());
                // 是否属于正常商品
                if (product.getIsDeleted() == 0 && product.getStatus() > 0) {
                    skuItems.add(skuItem);
                }else {
                    expireSkuItems.add(skuItem);
                }
            });
            componentShopItemList(shopMap, shopItems, k, skuItems);
            componentShopItemList(shopMap, expireSkuShopItems, k, expireSkuItems);
        });
        int skuCount = 0;
        for (ShopItem shopItem : shopItems) {
            skuCount += shopItem.getSkuItems().size();
        }
        CartProductResult cartProductResult = new CartProductResult();
        cartProductResult.setShopItems(shopItems);
        cartProductResult.setExpireSkuShopItems(expireSkuShopItems);
        cartProductResult.setSkuDetail(productMap);
        cartProductResult.setSkuCount(skuCount);
        return new BaseResult<>(cartProductResult);
    }

    private void componentShopItemList(Map<Integer, RenrenShopShop> shopMap, List<ShopItem> shopItems, Integer shopId, List<SkuItem> skuItems) {
        if (skuItems.size() > 0) {
            RenrenShopShop renrenShopShop = shopMap.get(shopId);
            ShopItem shopItem = new ShopItem();
            shopItem.setShopId(shopId);
            shopItem.setName(renrenShopShop.getName());
            shopItem.setLogo(renrenShopShop.getLogo());
            shopItem.setSkuItems(skuItems);
            shopItems.add(shopItem);
        }
    }

    /**
     * 查询商品信息
     *
     * @param ids ID列表
     * @return 结果
     */
    private List<Product> getProducts(List<Integer> ids) {
        List<Product> list = new LinkedList<>();
        List<RenrenShopGoods> shopGoods = renrenShopGoodsDao.selectByIds(ids);
        List<RenrenShopGoodsOption> goodsOptions = renrenShopGoodsOptionDao.selectByIds(ids);
        Map<Integer, List<RenrenShopGoodsOption>> optionsMap = skuGroupBySpuId(shopGoods.size(), goodsOptions);
        shopGoods.forEach(e -> {
            if (e.getHasOption()) {
                // 多规格商品
                if (optionsMap.containsKey(e.getId())) {
                    List<RenrenShopGoodsOption> options = optionsMap.get(e.getId());
                    list.addAll(goodOption2Product(e, options));
                }
            } else {
                // 单规格商品
                list.add(good2Product(e));
            }
        });
        return list;
    }

    /**
     * 多规格商品分组
     *
     * @param goodsOptions 多规格商品信息
     * @return 结果
     */
    private Map<Integer, List<RenrenShopGoodsOption>> skuGroupBySpuId(int size, List<RenrenShopGoodsOption> goodsOptions) {
        // 多规格商品SKU处理
        Map<Integer, List<RenrenShopGoodsOption>> optionsMap = new HashMap<>(size * 4 / 3 + 1);
        goodsOptions.forEach(e -> {
            if (!optionsMap.containsKey(e.getGoodsId())) {
                optionsMap.put(e.getGoodsId(), new LinkedList<>());
            }
            optionsMap.get(e.getGoodsId()).add(e);
        });
        return optionsMap;
    }

    /**
     * 多规格商品转SKU
     *
     * @param good    SPU
     * @param options 多规格
     * @return 结果
     */
    public List<Product> goodOption2Product(RenrenShopGoods good, List<RenrenShopGoodsOption> options) {
        List<Product> products = new ArrayList<>(options.size());
        BigDecimal minCostPrice = new BigDecimal("0");
        BigDecimal maxCostPrice = new BigDecimal("0");
        for (RenrenShopGoodsOption sku : options) {
            String id = good.getId() + "_" + sku.getId();
            String shopName = "";
            String skuName = good.getTitle() + "|" + sku.getTitle();
            Product product = new Product(id, good.getId(), sku.getId(), good.getShopId(), shopName, good.getTitle(),
                    skuName, good.getSubTitle(), good.getShortTitle(), good.getType(), good.getThumb(),
                    good.getThumbAll(), good.getVideo(), good.getVideoThumb(), good.getVideoType(), good.getStock(),
                    good.getSales(), good.getRealSales(), good.getContent(), good.getIsRecommand(), good.getIsHot(),
                    good.getIsNew(), sku.getPrice(), good.getMinPrice(), good.getMaxPrice(), good.getCostPrice(),
                    good.getCostPrice(), sku.getCostPrice(), sku.getOriginalPrice(), sku.getSales(), sku.getThumb(),
                    null, good.getStatus(), good.getIsDeleted());
            products.add(product);
            if (minCostPrice.compareTo(sku.getCostPrice()) > 0) {
                minCostPrice = sku.getCostPrice();
            }
            if (maxCostPrice.compareTo(sku.getCostPrice()) < 0) {
                maxCostPrice = sku.getCostPrice();
            }
        }
        for (Product p : products) {
            p.setSpuMinCostPrice(minCostPrice);
            p.setSpuMaxCostPrice(maxCostPrice);
        }
        return products;
    }

    /**
     * 单规格商品转sku
     *
     * @param good SPU
     * @return 结果
     */
    public Product good2Product(RenrenShopGoods good) {
        String id = good.getId() + "_" + good.getId();
        String shopName = "";
        return new Product(id, good.getId(), good.getId(), good.getShopId(), shopName, good.getTitle(),
                good.getTitle(), good.getSubTitle(), good.getShortTitle(), good.getType(), good.getThumb(),
                good.getThumbAll(), good.getVideo(), good.getVideoThumb(), good.getVideoType(), good.getStock(),
                good.getSales(), good.getRealSales(), good.getContent(), good.getIsRecommand(), good.getIsHot(),
                good.getIsNew(), good.getPrice(), good.getMinPrice(), good.getMaxPrice(), good.getCostPrice(),
                good.getCostPrice(), good.getCostPrice(), good.getOriginalPrice(), good.getSales(), null,
                null, good.getStatus(), good.getIsDeleted());
    }

}
